package com.jinke.api.modules.third.ezeeship2.service.impl;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.BooleanUtil;
import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.toolkit.ObjectUtils;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.jinke.api.common.api.CommonResult;
import com.jinke.api.common.api.ResultCode;
import com.jinke.api.common.exception.Asserts;
import com.jinke.api.common.util.CommonUtil;
import com.jinke.api.common.util.Global;
import com.jinke.api.modules.app.enums.BalanceLogType;
import com.jinke.api.modules.app.enums.OrderStatus;
import com.jinke.api.modules.app.enums.OrderType;
import com.jinke.api.modules.app.enums.ValidateStatus;
import com.jinke.api.modules.app.model.Order;
import com.jinke.api.modules.app.model.OrderParcel;
import com.jinke.api.modules.app.model.UserAddress;
import com.jinke.api.modules.app.response.CreateLabel2Response;
import com.jinke.api.modules.app.service.IUserOrderTaskService;
import com.jinke.api.modules.app.service.OrderParcelService;
import com.jinke.api.modules.app.service.OrderService;
import com.jinke.api.modules.app.service.UserRechargeService;
import com.jinke.api.modules.app.util.MathUtil;
import com.jinke.api.modules.app.util.ParcelUtil;
import com.jinke.api.modules.app.util.OssUtil;
import com.jinke.api.modules.base.service.ThirdService;
import com.jinke.api.modules.third.ezeeship.model.request.EstimateRateRequest;
import com.jinke.api.modules.third.ezeeship.model.response.CreateLabelResponse;
import com.jinke.api.modules.third.ezeeship.model.response.EstimateRateResponse;
import com.jinke.api.modules.third.ezeeship.model.response.TrackingResponse;
import com.jinke.api.modules.third.ezeeship.model.response.ValidateResponse;
import com.jinke.api.modules.third.ezeeship2.service.EzeeShip2Service;
import com.jinke.api.modules.third.ezeeship2.util.EzeeShip2Util;
import com.jinke.api.modules.ums.model.Channel;
import com.jinke.api.modules.ums.model.UmsAdmin;
import com.jinke.api.modules.ums.model.UserChannel;
import com.jinke.api.modules.ums.service.ChannelService;
import com.jinke.api.modules.ums.service.IApiLogService;
import com.jinke.api.modules.ums.service.UmsAdminService;
import com.jinke.api.modules.ums.service.UserChannelService;
import com.jinke.api.modules.ums.vo.UserChannelVO;
import com.jinke.api.security.util.ApiUserUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;

/**
 * <p>
 * 服务实现类
 * </p>
 *
 * @author macro
 * @since 2024-01-13
 */
@Service
@Slf4j
public class EzeeShip2ServiceImpl implements EzeeShip2Service {
    @Resource
    private UmsAdminService umsAdminService;
    @Resource
    private OrderParcelService orderParcelService;
    @Resource
    private UserRechargeService userRechargeService;
    @Resource
    private OssUtil ossUtil;
    @Resource
    private IApiLogService iApiLogService;
    @Resource
    private OrderService orderService;
    @Resource
    private ThirdService thirdService;
    @Resource
    private UserChannelService userChannelService;
    @Resource
    private ChannelService channelService;
    @Resource
    private IUserOrderTaskService iUserOrderTaskService;
    @Resource
    private EzeeShip2Util ezeeShip2Util;

    @Override
    public CommonResult estimateRate(EstimateRateRequest request) {
        Integer  userId = ApiUserUtil.getUserId();
        return estimateRate(request, userId);
    }

    @Override
    public CommonResult estimateRate(EstimateRateRequest request, Integer userId) {
        try {
            if (request.getTo().getStateCode()!=null&&request.getTo().getStateCode().equals("Missouri")){
                request.getTo().setStateCode("MO");
            }
            if (request.getTo().getState()!=null&&request.getTo().getState().equals("Missouri")){
                request.getTo().setState("MO");
            }
            if (request.getFrom().getState()!=null&&request.getFrom().getState().equals("Missouri")){
                request.getFrom().setState("MO");
            }
            if (request.getFrom().getStateCode()!=null&&request.getFrom().getStateCode().equals("Missouri")){
                request.getFrom().setStateCode("MO");
            }
            //默认
            request.getExtra().setSignatureOption("4");
            request.getExtra().setBatteryType(null);
        }catch (Exception e){
            log.error("ezze2转出错");
        }

        List<EstimateRateRequest.Parcel> parcels = request.getParcels();
        for (EstimateRateRequest.Parcel parcel : parcels) {
            parcel.setPackageCode("your_package");
        }

        fillResidential(request, userId);
        UserChannelVO userChannelVO = request.getUserChannelVO();
        Channel channel = userChannelVO.getChannel();
        request.setServiceCode(channel.getChannelCode());
        BigDecimal rateAmount;
        try {
            rateAmount = getPrice(request, userId, userChannelVO);
        } catch (Exception e) {
            return CommonResult.failed(e.getMessage());
        }
        if (rateAmount.compareTo(new BigDecimal("0")) <= 0) {
            return CommonResult.failed("系统异常，请联系管理人员");
        }
        EstimateRateResponse.Data newData = new EstimateRateResponse.Data();
        newData.setRate(rateAmount);
        return CommonResult.success(newData);
    }

    private BigDecimal getPrice(EstimateRateRequest request, Integer userId, UserChannelVO vo) {
        BigDecimal rateAmount = new BigDecimal("0");
        String strResult =  ezeeShip2Util.estimateRate(request);
        if (StringUtils.isNotEmpty(strResult)) {
            EstimateRateResponse estimateRateResponse = JSONUtil.toBean(strResult, EstimateRateResponse.class);
            if ("ERR".equals(estimateRateResponse.getResult())) {
                String errormessage = StringUtils.isNotBlank(estimateRateResponse.getZhMessage()) ?
                        estimateRateResponse.getZhMessage() : estimateRateResponse.getMessage();
                throw new RuntimeException(errormessage);
            }
            EstimateRateResponse.Data data = estimateRateResponse.getData();
            BigDecimal rate = data.getRate();
            rateAmount = thirdService.calcRate(userId, vo, rate);
        }
        return rateAmount;
    }

    @Override
    public CommonResult createLabel(EstimateRateRequest request) {
        Integer userId = ApiUserUtil.getUserId();
        return createLabel(request, userId);
    }

    @Override
    public CommonResult createLabel(EstimateRateRequest request, Integer userId) {
        if (StringUtils.isBlank(request.getOrderNO())) {
            request.setOrderNO( CommonUtil.getOrderNo());
        }

        UserChannelVO userChannelVO = request.getUserChannelVO();
        Channel channel = userChannelVO.getChannel();
        request.setServiceCode(channel.getChannelCode());
        fillResidential(request, userId);
        //估价
        BigDecimal rateAmount;
        try {
            rateAmount = getPrice(request, userId, userChannelVO);
        } catch (Exception e) {
            return CommonResult.failed(e.getMessage());
        }
        UmsAdmin umsAdmin = umsAdminService.getById(userId);
        if (ObjectUtils.isEmpty(umsAdmin) || rateAmount.compareTo(new BigDecimal("0")) <= 0) {
            return CommonResult.failed("系统异常,请联系管理员");
        }
        BigDecimal totalAmount = umsAdmin.getBalance().add(umsAdmin.getCreditBalance());
        if (totalAmount.compareTo(rateAmount) < 0) {
            return CommonResult.failed("Insufficient Balance");
        }
        Integer labelSize = request.getLabelSize();
        if (labelSize == null) {
            request.setLabelSize(1);
        }
        String strResult =  ezeeShip2Util.createLabel(request);
        CreateLabelResponse.Data createLabelResponseData;
        Order order = new Order();
        BeanUtils.copyProperties(request, order);
        order.setId(request.getOrderId());
        order.setUserId(userId);
        if (ObjectUtils.isNotEmpty(umsAdmin.getSellerId())) {
            order.setSellerId(umsAdmin.getSellerId());
        }
        if (StringUtils.isNotBlank(strResult)) {
            CreateLabelResponse createLabelResponse = JSONUtil.toBean(strResult, CreateLabelResponse.class);
            if ("ERR".equals(createLabelResponse.getResult())) {
                String errorMessage = StringUtils.isNotEmpty(createLabelResponse.getMessage()) ? createLabelResponse.getMessage() : createLabelResponse.getZhMessage();
                //包涵余额不足提示信息
                if (errorMessage.contains("Insufficient balance")) {
                    errorMessage = "Service in Maintenace, Please Contact Support";
                }
                if (order.getId() != null) {
                    orderService.update(new LambdaUpdateWrapper<Order>().eq(Order::getId, order.getId()).set(Order::getErrMsg, errorMessage));
                }
                return CommonResult.failed(errorMessage);
            }
            createLabelResponseData = createLabelResponse.getData();
            order.setOrderNo(request.getOrderNO());
            //设置错误信息为空
            order.setErrMsg("");
            BigDecimal rate = createLabelResponseData.getRate();
            BigDecimal finalRate = thirdService.calcRate(userId, request.getUserChannelVO(), rate);

            order.setRate(finalRate);
            order.setOriginFee(rate);


            // 扣钱
            if (finalRate != null && BigDecimal.ZERO.compareTo(finalRate) < 0) {
                userRechargeService.decrTransfer(userId, finalRate, BalanceLogType.CONSUME, "寄件", order.getOrderNo(), order.getObjectId(), channel,null);
            }


            String pdfUrl = createLabelResponseData.getPdfUrl();
            // 上传到oss
            String objectId = createLabelResponseData.getObjectId();
            ossUtil.upload("pdf", objectId + ".pdf", pdfUrl);

            String newPdfUrl = Global.PRINT_LABEL_API + objectId;

            // order.setCreateTime(createLabelResponseData.getCreateTime());

            order.setFromCity(request.getFrom().getCity());
            order.setFromEmail(request.getFrom().getEmail());
            order.setFromCompany(request.getFrom().getCompany());
            order.setFromPhone(request.getFrom().getPhone());
            order.setFromAddressLine2(request.getFrom().getAddressLine2());
            order.setFromAddressLine1(request.getFrom().getAddressLine1());
            order.setFromCountryCode(request.getFrom().getCountryCode());
            order.setFromZipCode(request.getFrom().getZipCode());
            order.setFromPersonName(request.getFrom().getPersonName());
            order.setFromStateCode(request.getFrom().getStateCode());

            try {
                order.setReference(request.getExtra().getReference());
                order.setReference2(request.getExtra().getReference2());
            }catch (Exception e){
                log.error("设置reference出错了");
            }
            EstimateRateRequest.Address requestTo = request.getTo();
            order.setToCity(requestTo.getCity());
            order.setToEmail(requestTo.getEmail());
            order.setToCompany(requestTo.getCompany());
            order.setToPhone(requestTo.getPhone());
            order.setToAddressLine2(requestTo.getAddressLine2());
            order.setToAddressLine1(requestTo.getAddressLine1());
            order.setToCountryCode(requestTo.getCountryCode());
            order.setToZipCode(requestTo.getZipCode());
            order.setToPersonName(requestTo.getPersonName());
            order.setToStateCode(requestTo.getStateCode());
            order.setOrderType(OrderType.API);

            int status = createLabelResponseData.getStatus();
            order.setPdfUrl(newPdfUrl);
            order.setStatus(OrderStatus.RECENT.getValue());
            order.setObjectId(objectId);
            order.setSellerId(umsAdmin.getSellerId());
            order.setChannelId(request.getChannelId());
            order.setCreateTime(LocalDateTime.now());
            if (BooleanUtil.isTrue(requestTo.getIsValid())) {
                order.setValidateStatus(ValidateStatus.defaultEnum(requestTo.getIsResidential()));
            } else {
                order.setValidateStatus(ValidateStatus.UN_VALIDATE);
            }

            BigDecimal earnestRate = umsAdmin.getEarnestRate();
            BigDecimal subEarnestBalance = MathUtil.formatBigDecimal(finalRate.multiply(earnestRate));
            order.setEarnest(subEarnestBalance);

            orderService.saveOrUpdate(order);
            //定时任务表插入一条数据
            iUserOrderTaskService.saveByOrderId(order.getId());

            Integer orderId = order.getId();
            List<String> trackingNumber = createLabelResponseData.getTrackingNumber();
            List<String> trackingUrl = createLabelResponseData.getTrackingUrl();
            List<String> labelUrls = createLabelResponseData.getLabelUrl();
            List<EstimateRateRequest.Parcel> parcels = request.getParcels();

            List<OrderParcel> orderParcels = ParcelUtil.getOrderParcels(parcels, orderId, userId);

            //更新包裹信息
            updateParcel(orderId, trackingNumber, trackingUrl, labelUrls, orderParcels);


            CreateLabelResponse.Data newCreateLabelResponseData = new CreateLabelResponse.Data();
            newCreateLabelResponseData.setRate(finalRate);

            CreateLabel2Response.FeeDetail newFeeDetail = new CreateLabel2Response.FeeDetail();
            newFeeDetail.setBaseRate(finalRate);
            newCreateLabelResponseData.setFeeDetail(newFeeDetail);

            newCreateLabelResponseData.setRate(finalRate);
            newCreateLabelResponseData.setStatus(status);
            newCreateLabelResponseData.setCreateTime(createLabelResponseData.getCreateTime());
            newCreateLabelResponseData.setObjectId(createLabelResponseData.getObjectId());
            newCreateLabelResponseData.setPdfUrl(newPdfUrl);
            newCreateLabelResponseData.setTrackingNumber(trackingNumber);
            String labelUrl = Global.PRINT_LABEL_API + objectId;
            newCreateLabelResponseData.setLabelUrl(Arrays.asList(labelUrl));

            return CommonResult.success(newCreateLabelResponseData);
        }
        return CommonResult.failed(ResultCode.ERROR_API);
    }

    /**
     * 更新包裹 信息
     * @param orderId
     * @param trackingNumber
     * @param trackingUrl
     * @param labelUrls
     * @param orderParcels
     */
    @Transactional
    void updateParcel(Integer orderId, List<String> trackingNumber, List<String> trackingUrl, List<String> labelUrls, List<OrderParcel> orderParcels) {
        try {

            for (int i = 0; i < orderParcels.size(); i++) {
                OrderParcel orderParcel = orderParcels.get(i);
                String trackNumber = i < trackingNumber.size()? trackingNumber.get(i) : trackingNumber.get(0);
                orderParcel.setTrackingNumber(StringUtils.isNotBlank(trackNumber)? trackNumber : trackingNumber.get(0));
                String tkUrl = i < trackingUrl.size()? trackingUrl.get(i) : trackingUrl.get(0);
                orderParcel.setTrackingUrl(StringUtils.isNotBlank(tkUrl)? tkUrl : trackingUrl.get(0));
                String curlLabelUrl = i < labelUrls.size()? labelUrls.get(i) : labelUrls.get(0);
                if (StringUtils.isNotBlank(curlLabelUrl) && i < 3) {
                    String tmpName = CommonUtil.getOrderNo();
                    ossUtil.upload("pdf", tmpName + ".pdf", curlLabelUrl);
                    String newLabelUrl = Global.PRINT_LABEL_API + tmpName;
                    orderParcel.setLabelUrl(newLabelUrl);
                } else {
                    orderParcel.setLabelUrl(curlLabelUrl);
                }
            }
        }catch (Exception e){
            log.error("ezeeship2下单时转包的信息"+e.getMessage());
        }
        // 删除原来的包裹信息
        orderParcelService.remove(new LambdaQueryWrapper<OrderParcel>().eq(OrderParcel::getOrderId, orderId));
        // 入库
        orderParcelService.saveBatch(orderParcels);
    }

    @Override
    public void fillResidential(EstimateRateRequest request, Integer userId) {
        if (!BooleanUtil.isTrue(request.getTo().getIsValid())) {
            // 校验地址
            CommonResult validate = validate(request.getTo());
            if (validate.isSucess()) {
                Object data = validate.getData();
                if (data instanceof ValidateResponse.TrackingData) {
                    EstimateRateRequest.Address requestTo = request.getTo();
                    ValidateResponse.TrackingData t = (ValidateResponse.TrackingData) data;
                    requestTo.setIsValid(t.getIsValid());
                    Boolean isResidential = t.getIsResidential();
                    requestTo.setIsResidential(isResidential);
                    if (BooleanUtil.isTrue(isResidential)) { // 如果客户选择fedex ground ,并且是住宅地址， 需要fedex ground 改成fedex home delivery
                        Channel channel = request.getUserChannelVO().getChannel();
                        if ("fedex_ground".equals(channel.getChannelCode())) {
                            // 获取用户权限
                            List<UserChannel> userChannels = userChannelService.list(new LambdaQueryWrapper<UserChannel>()
                                    .eq(UserChannel::getUserId, userId)
                            );
                            if (CollectionUtil.isEmpty(userChannels)) {
                                return;
                            }

                            //根据渠道id 获取渠道列表
                            List<Channel> channels = channelService.list(new LambdaQueryWrapper<Channel>()
                                    .eq(Channel::getChannelCode, "fedex_home_delivery")
                                    .in(Channel::getId, userChannels.stream().map(UserChannel::getChannelId).collect(Collectors.toList()))
                            );
                            if (CollectionUtil.isNotEmpty(channels)) {
                                Channel newChannel = channels.get(0);
                                UserChannel userChannel = userChannels.stream().filter(x -> {
                                    return x.getChannelId() == newChannel.getId().intValue();
                                }).findFirst().get();
                                UserChannelVO userChannelVO = new UserChannelVO();
                                BeanUtils.copyProperties(userChannel, userChannelVO);
                                userChannelVO.setChannel(newChannel);
                                request.setChannelId(newChannel.getId());
                                request.setUserChannelVO(userChannelVO);
                                System.out.println(111);
                            }

                        }
                    }
                }
            }
        }
    }

    @Override
    public CommonResult getLabel(String objectId) {
        return getLabel(objectId, null);
    }

    @Override
    public CommonResult getLabel(String objectId, Integer userId) {
        log.info(JSONUtil.toJsonStr(objectId));
        String strResult =  ezeeShip2Util.getLabel(objectId);
        CreateLabelResponse.Data createLabelResponseData = new CreateLabelResponse.Data();
        if (StringUtils.isNotBlank(strResult)) {

            if (userId == null) {
                userId = ApiUserUtil.getUserId();
            }

            Order order = orderService.getOne(new LambdaQueryWrapper<Order>()
                    .eq(Order::getObjectId, objectId)
                    .eq(Order::getUserId, userId)
            );

            if (order == null) {
                return CommonResult.success(createLabelResponseData);
            }
            createLabelResponseData = JSONUtil.toBean(strResult, CreateLabelResponse.Data.class);
            CreateLabelResponse.Data newCreateLabelResponseData = new CreateLabelResponse.Data();
            newCreateLabelResponseData.setObjectId(objectId);
            newCreateLabelResponseData.setPdfUrl(order.getPdfUrl());
            BigDecimal finalRate = order.getRate();
            newCreateLabelResponseData.setRate(finalRate);
            newCreateLabelResponseData.setStatus(createLabelResponseData.getStatus());
            CreateLabel2Response.FeeDetail newFeeDetail = new CreateLabel2Response.FeeDetail();
            newFeeDetail.setBaseRate(finalRate);
            newCreateLabelResponseData.setFeeDetail(newFeeDetail);

            newCreateLabelResponseData.setCreateTime(createLabelResponseData.getCreateTime());
            newCreateLabelResponseData.setTrackingNumber(createLabelResponseData.getTrackingNumber());

            String labelUrl = Global.PRINT_LABEL_API + objectId;
            newCreateLabelResponseData.setLabelUrl(Arrays.asList(labelUrl));

            return CommonResult.success(newCreateLabelResponseData);

        }

        return CommonResult.success();
    }

    @Override
    public CommonResult cancelLabel(String objectId,String orderNo) {
        // 调用接口
        String strResult =  ezeeShip2Util.cancelLabel(objectId,orderNo);
        if (StringUtils.isNotBlank(strResult)) {
            CreateLabelResponse createLabelResponse = JSONUtil.toBean(strResult, CreateLabelResponse.class);
            if (!"OK".equals(createLabelResponse.getResult())) {
                //未取消成功抛出异常
                Asserts.fail(createLabelResponse.getMessage());
            }
        }
        return CommonResult.success();
    }

    @Override
    public CommonResult tracking(String trackingNumber) {
        // 调用接口
        String strResult =  ezeeShip2Util.tracking(trackingNumber);
        if (StringUtils.isNotBlank(strResult)) {
            TrackingResponse trackingResponse = JSONUtil.toBean(strResult, TrackingResponse.class);
            if (!"OK".equals(trackingResponse.getResult())) {
                return CommonResult.failed(trackingResponse.getMessage());
            } else {
                return CommonResult.success(trackingResponse.getData());
            }
        }
        return CommonResult.success();
    }

    @Override
    public CommonResult validate(UserAddress userAddress) {
        EstimateRateRequest.Address address = new EstimateRateRequest.Address();
        address.setStateCode(userAddress.getStateCode());
        address.setPersonName(userAddress.getPersonName());
        address.setAddressLine2(userAddress.getAddressLine2());
        address.setAddressLine1(userAddress.getAddressLine1());
        address.setCity(userAddress.getCity());
        address.setZipCode(userAddress.getZipCode());
        address.setPhone(userAddress.getPhone());
        address.setCompany(userAddress.getCompany());
        address.setCountryCode(userAddress.getCountryCode());
        return validate(address);

    }

    @Override
    public CommonResult validate(EstimateRateRequest.Address address) {
        String strResult =  ezeeShip2Util.validateAddress(address);
        if (StringUtils.isNotBlank(strResult)) {
            ValidateResponse trackingResponse = JSONUtil.toBean(strResult, ValidateResponse.class);
            if (!"OK".equals(trackingResponse.getResult())) {
                return CommonResult.failed(trackingResponse.getMessage());
            } else {
                return CommonResult.success(trackingResponse.getData());
            }
        }
        return CommonResult.success();
    }
    @Override
    public CommonResult cancelInsurance(String insuranceId) {

        return CommonResult.success();
    }

}
